package com.zeta.gateway.filter;

import cn.hutool.core.util.IdUtil;
import org.slf4j.MDC;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import org.zetaframework.core.constants.Constants;
import reactor.core.publisher.Mono;

/**
 * 链路追踪过滤器
 *
 * @author gcc
 */
@Configuration
public class TraceFilter implements GlobalFilter, Ordered {

    /**
     * 执行过滤器逻辑
     * <p>
     * 说明：
     * <pre>
     * 1. 生成全局唯一的traceId
     * 2. 将traceId放入MDC上下文中，用于日志追踪
     * 3. 将traceId添加到请求头中，传递给下游微服务
     * 4. 在请求处理完成后清理MDC中的traceId
     *
     * 后续微服务，通过{@link org.zetaframework.satoken.interceptor.TraceInterceptor}从请求头中获取traceId并设置到MDC中
     * </pre>
     *
     * @param exchange ServerWebExchange对象，代表一次HTTP交换
     * @param chain 过滤器链
     * @return Mono<Void> 异步处理结果
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 生成全局唯一的追踪ID
        String traceId = IdUtil.fastSimpleUUID();

        // 将traceId放入MDC中，用于日志追踪
        MDC.put(Constants.TRACE_ID, traceId);
        try {
            // 将traceId添加到请求头中，传递给下游服务
            ServerHttpRequest request = exchange.getRequest().mutate()
                    .headers(headers -> headers.add(Constants.TRACE_ID, traceId))
                    .build();
            // 继续执行过滤器链，使用修改后的请求
            return chain.filter(exchange.mutate().request(request).build());
        } finally {
            // 清理MDC中的traceId，防止内存泄漏
            MDC.remove(Constants.TRACE_ID);
        }
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}
